﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Pavilion;

namespace Pavilion.Control
{
    public delegate void ControlMovedHandler(Control control, Point position);

    public class MoveComponent
    {
        private Control control;
        private Panel movedPanel;
        private Point previousPosition, positionMoved;
        private MouseObjectHandler moved_PressedDel;
        private Action<MouseCursor> dropped_MouseReleaseDel, moved_MouseMovedDel;

        private event ControlMovedHandler moved, dropped;

        public MoveComponent(Control control)
        {
            this.control = control;
        }

        /// <summary>
        /// Begins the moving process.
        /// </summary>
        private void BeginMoving()
        {
            if (moved_MouseMovedDel != null || dropped_MouseReleaseDel != null)
                return;

            previousPosition = new Point((int)RootControl.Instance.MouseCursor.Position.X, (int)RootControl.Instance.MouseCursor.Position.Y);

            moved_MouseMovedDel = new Action<MouseCursor>(OnMoved);
            RootControl.Instance.MouseCursor.MouseMoved += moved_MouseMovedDel;

            dropped_MouseReleaseDel = new Action<MouseCursor>(OnDropped);
            RootControl.Instance.MouseCursor.LeftMouseReleased += dropped_MouseReleaseDel;
        }

        /// <summary>
        /// Ends the moving process. Returns true if the control has moved.
        /// </summary>
        private bool EndMoving()
        {
            if (moved_MouseMovedDel != null)
            {
                RootControl.Instance.MouseCursor.MouseMoved -= moved_MouseMovedDel;
                moved_MouseMovedDel = null;
            }

            if (dropped_MouseReleaseDel != null)
            {
                RootControl.Instance.MouseCursor.LeftMouseReleased -= dropped_MouseReleaseDel;
                dropped_MouseReleaseDel = null;
            }

            if (movedPanel != null)
            {
                movedPanel.DetachFromParent();
                movedPanel = null;

                return true;
            }

            return false;
        }

        private void ActivateMoving()
        {
            moved_PressedDel = new MouseObjectHandler(Moved_Pressed);
            control.Input.MousePress += moved_PressedDel;
        }

        private void DeactivateMoving()
        {
            control.Input.MousePress -= moved_PressedDel;
            moved_PressedDel = null;
        }

        private void ActivateMovingPanel()
        {
            movedPanel = new Panel(control.ScreenBounds);
            movedPanel.OutlineColor = Color.Aqua;
            movedPanel.BackgroundColor = Color.Transparent;
            RootControl.Instance.Collection.Add(movedPanel);
        }

        private void UpdateMovingPanel()
        {
            int xDif = (int)(RootControl.Instance.MouseCursor.Position.X - previousPosition.X);
            int yDif = (int)(RootControl.Instance.MouseCursor.Position.Y - previousPosition.Y);

            movedPanel.Position = positionMoved = new Point(movedPanel.Position.X + xDif, movedPanel.Position.Y + yDif);
            previousPosition = new Point((int)RootControl.Instance.MouseCursor.Position.X, (int)RootControl.Instance.MouseCursor.Position.Y);
        }

        public event ControlMovedHandler Moved
        {
            add
            {
                if (moved == null && dropped == null)
                    ActivateMoving();

                moved += value;
            }
            remove
            {
                moved -= value;

                if (moved == null && dropped == null)
                    DeactivateMoving();
            }
        }

        public event ControlMovedHandler Dropped
        {
            add
            {
                if (moved == null && dropped == null)
                    ActivateMoving();

                dropped += value;
            }
            remove
            {
                dropped -= value;

                if (moved == null && dropped == null)
                    DeactivateMoving();
            }
        }

        private void OnDropped(MouseCursor mouseCursor)
        {
            bool ifMoved = EndMoving();

            if (dropped != null && ifMoved)
                dropped(control, positionMoved);
        }

        private void OnMoved(MouseCursor mouseCursor)
        {
            if (movedPanel == null)
                ActivateMovingPanel();

            UpdateMovingPanel();

            if (moved != null)
                moved(control, positionMoved);
        }

        private void Moved_Pressed(object sender, MouseCursor mouseCursor)
        {
            if (Mouse.GetState().LeftButton != ButtonState.Pressed)
                return;

            BeginMoving();
        }
    }
}
